package cn.o.app.ui;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.FragmentActivity;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.widget.FrameLayout;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.Toast;
import cn.o.app.OWrapper;
import cn.o.app.db.DbQueue;
import cn.o.app.db.IDbQueue;
import cn.o.app.db.IDbQueueListener;
import cn.o.app.db.IDbQueueOwner;
import cn.o.app.db.IDbTask;
import cn.o.app.download.IDownloadQueueOwner;
import cn.o.app.download.IDownloadTask;
import cn.o.app.event.Dispatcher;
import cn.o.app.event.listener.OnActivityResultListener;
import cn.o.app.net.INetQueue;
import cn.o.app.net.INetQueueListener;
import cn.o.app.net.INetQueueOwner;
import cn.o.app.net.INetTask;
import cn.o.app.net.NetQueue;
import cn.o.app.net.NetTask.CookieExpiredException;
import cn.o.app.queue.IQueue;
import cn.o.app.socket.ISocketQueueOwner;
import cn.o.app.socket.ISocketTask;
import cn.o.app.task.IStopable;
import cn.o.app.task.IStopableManager;
import cn.o.app.ui.pattern.IPatternDataProvider;
import cn.o.app.ui.pattern.IPatternOwner;
import cn.o.app.ui.pattern.IPatternView;

@SuppressWarnings("unchecked")
public class OActivity extends FragmentActivity implements IFragmentManager,
		INetQueueOwner, IPatternOwner, IDbQueueOwner, IToastOwner,
		IStopableManager, IActivityResultCatcher {

	// 暂停手势密码检测3分钟
	public static final long PATTERN_DISABLE_SHORT = 180000L;

	// 暂停手势密码检测5分钟
	public static final long PATTERN_DISABLE_LONG = 300000L;

	protected DbQueue mDbQueue;

	protected NetQueue mNetQueue;

	protected Handler mWaitingViewHandler;

	protected Runnable mWaitingViewDelayer;

	protected ViewGroup mWaitingView;

	protected WindowManager.LayoutParams mWaitingViewParams;

	protected Animation mWaitingViewFadeInAnim;

	protected Animation mWaitingViewFadeOutAnim;

	protected boolean mWaitingViewShowing;

	protected boolean mBusy;

	protected List<IStateView> mBindViews;

	protected static long sLastActiveTime = 0;

	protected long mNoPatternDeadLine = 0;

	protected long mNoPatternDuration = 0;

	protected Handler mActiveHandler = new Handler();

	protected Runnable mActiveRunnable = new Runnable() {

		@Override
		public void run() {
			sLastActiveTime = System.currentTimeMillis();
			mActiveHandler.removeCallbacksAndMessages(null);
			mActiveHandler.postDelayed(mActiveRunnable, 1000);
		}
	};

	protected ViewGroup mPatternView;

	protected WindowManager.LayoutParams mPatternViewParams;

	protected Animation mPatternViewFadeInAnim;

	protected Animation mPatternViewFadeOutAnim;

	protected boolean mPatternViewShowing;

	protected List<IStopable> mBindStopables;

	protected OToast mToast;

	protected boolean mRunning;

	protected Toast mSysToast;

	protected Dispatcher mDispatcher = new Dispatcher();

	public Context getContext() {
		return this;
	}

	public void toast(CharSequence s) {
		if (!mRunning) {
			return;
		}
		if (mSysToast == null) {
			mSysToast = Toast.makeText(this, "", Toast.LENGTH_SHORT);
		}
		if (s == null) {
			mSysToast.cancel();
		} else {
			if (s.equals("")) {
				mSysToast.cancel();
			} else {
				mSysToast.setText(s);
				mSysToast.show();
			}
		}
	}

	public void toast(int resId) {
		if (!mRunning) {
			return;
		}
		if (mSysToast == null) {
			mSysToast = Toast.makeText(this, "", Toast.LENGTH_SHORT);
		}
		if (resId == 0) {
			mSysToast.cancel();
		} else {
			mSysToast.setText(resId);
			mSysToast.show();
		}
	}

	public boolean isBusy() {
		return mBusy;
	}

	public void setBusy(boolean busy) {
		mBusy = busy;
		postUpdateWaitingViewState();
	}

	@Override
	public OToast getToast() {
		return mToast;
	}

	@Override
	public void bind(IStopable stopable) {
		OWrapper.bind(this, stopable);
	}

	@Override
	public void disablePattern(long duration) {
		mNoPatternDuration = duration;
	}

	@Override
	public void enablePattern() {
		mNoPatternDeadLine = 0;
		mNoPatternDuration = 0;
	}

	@Override
	public boolean checkPattern() {
		return false;
	}

	@Override
	public void doCheckPattern() {
		if (!this.checkPattern()) {
			return;
		}
		if (!(this.getApplicationContext() instanceof IPatternDataProvider)) {
			return;
		}
		IPatternDataProvider patternDataProvider = (IPatternDataProvider) this
				.getApplicationContext();
		if (patternDataProvider.isLogined()) {
			if (patternDataProvider.isPatternEnabled()) {
				if (sLastActiveTime == 0
						|| (System.currentTimeMillis() - sLastActiveTime) > patternDataProvider
								.getPatternPeriod()) {
					showPattern();
				}
			}
		}
	}

	@Override
	public IPatternView newPattern() {
		return null;
	}

	@Override
	public void showPattern() {
		if (this.mPatternViewShowing) {
			return;
		}
		if (mPatternView == null) {
			FrameLayout realPatternView = new FrameLayout(this);
			this.mPatternViewParams = new WindowManager.LayoutParams(
					ViewGroup.LayoutParams.MATCH_PARENT,
					ViewGroup.LayoutParams.MATCH_PARENT,
					WindowManager.LayoutParams.TYPE_APPLICATION,
					WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
					PixelFormat.TRANSPARENT);
			View virtualPatternView = (View) this.newPattern();
			realPatternView.addView(virtualPatternView,
					new FrameLayout.LayoutParams(
							FrameLayout.LayoutParams.MATCH_PARENT,
							FrameLayout.LayoutParams.MATCH_PARENT));
			this.mPatternView = realPatternView;
			this.mPatternViewFadeInAnim = new AlphaAnimation(0, 1);
			this.mPatternViewFadeInAnim.setDuration(200);
			this.mPatternViewFadeInAnim.setFillAfter(true);
			this.mPatternViewFadeOutAnim = new AlphaAnimation(1, 0);
			this.mPatternViewFadeOutAnim.setDuration(200);
			this.mPatternViewFadeOutAnim.setFillAfter(true);
			mPatternViewFadeOutAnim
					.setAnimationListener(new AnimationListener() {

						@Override
						public void onAnimationStart(Animation animation) {

						}

						@Override
						public void onAnimationRepeat(Animation animation) {

						}

						@Override
						public void onAnimationEnd(Animation animation) {
							hidePatternNow();
						}
					});
		}
		View virtualPatternView = this.mPatternView.getChildAt(0);
		((IPatternView) virtualPatternView).refresh();
		this.getWindowManager().addView(mPatternView, mPatternViewParams);
		virtualPatternView.clearAnimation();
		virtualPatternView.startAnimation(mPatternViewFadeInAnim);
		mPatternViewShowing = true;
	}

	@Override
	public void hidePattern() {
		if (!mPatternViewShowing) {
			return;
		}
		View virtualPatternView = this.mPatternView.getChildAt(0);
		virtualPatternView.clearAnimation();
		virtualPatternView.startAnimation(mPatternViewFadeOutAnim);
	}

	protected void hidePatternNow() {
		if (!mPatternViewShowing) {
			return;
		}
		this.getWindowManager().removeView(mPatternView);
		this.mPatternViewShowing = false;
	}

	@Override
	public void bind(IStateView stateView) {
		OWrapper.bind(this, stateView);
	}

	@Override
	public void setContentView(int layoutResID) {
		super.setContentView(layoutResID);
		this.bindStateViews();
	}

	@Override
	public void setContentView(View view) {
		super.setContentView(view);
		this.bindStateViews();
	}

	@Override
	public void setContentView(View view, LayoutParams params) {
		super.setContentView(view, params);
		bindStateViews();
	}

	protected void bindStateViews() {
		OWrapper.bindStateViews(this, this.getWindow().getDecorView());
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		this.requestWindowFeature(Window.FEATURE_NO_TITLE);
		super.onCreate(savedInstanceState);
		mNetQueue = new NetQueue();
		mNetQueue.setContext(this);
		mNetQueue.addListener(mNetQueueListener);
		mDbQueue = new DbQueue();
		mDbQueue.setContext(this);
		mDbQueue.addListener(mDbQueueListener);

		this.mWaitingViewShowing = false;

	}

	@Override
	protected void onStart() {
		super.onStart();
		OWrapper.dispatchStart(this);
		if (this.getApplicationContext() instanceof IPatternDataProvider) {
			((IPatternDataProvider) this.getApplicationContext()).isLogined();
		}
		mActiveHandler.postDelayed(mActiveRunnable, 1000);
	}

	@Override
	protected void onResume() {
		super.onResume();
		OWrapper.dispatchResume(this);
		if (mNoPatternDeadLine == 0) {
			doCheckPattern();
		} else {
			if (mNoPatternDeadLine < System.currentTimeMillis()) {
				doCheckPattern();
				mNoPatternDeadLine = 0;
			}
		}
		enablePattern();
		mRunning = true;
	}

	@Override
	protected void onPause() {
		mRunning = false;
		OWrapper.dispatchPause(this);
		super.onPause();
	}

	@Override
	protected void onStop() {
		OWrapper.dispatchStop(this);
		mActiveHandler.removeCallbacksAndMessages(null);
		long currentTime = System.currentTimeMillis();
		sLastActiveTime = currentTime;
		if (mNoPatternDuration != 0) {
			mNoPatternDeadLine = currentTime + mNoPatternDuration;
			mNoPatternDuration = 0;
		}
		super.onStop();
	}

	@Override
	protected void onDestroy() {
		mActiveHandler.removeCallbacksAndMessages(null);
		mNetQueue.removeListener(mNetQueueListener);
		mNetQueue.clear();
		if (mWaitingViewHandler != null) {
			mWaitingViewHandler.removeCallbacksAndMessages(null);
		}
		OWrapper.dispatchDestroy(this);
		hidePatternNow();
		hideWaitingNow();
		super.onDestroy();
	}

	@Override
	public void onBackPressed() {
		if (this.onInterceptBackPressed()) {
			return;
		}
		super.onBackPressed();
	}

	public boolean onInterceptBackPressed() {
		if (OWrapper.interceptBackPressed(this)) {
			return true;
		}
		if (mBusy) {
			this.setBusy(false);
			return true;
		}
		return false;
	}

	public INetQueue getNetQueue() {
		return this.mNetQueue;
	}

	protected INetQueueListener mNetQueueListener = new INetQueueListener() {

		@Override
		public void onRunStateChanged(IQueue queue) {
			postUpdateWaitingViewState();
		}
	};

	public IDbQueue getDbQueue() {
		return mDbQueue;
	}

	protected IDbQueueListener mDbQueueListener = new IDbQueueListener() {

		@Override
		public void onRunStateChanged(IQueue queue) {
			postUpdateWaitingViewState();
		}
	};

	protected void postUpdateWaitingViewState() {
		if (this.mWaitingViewHandler == null) {
			this.mWaitingViewHandler = new Handler();
		}
		if (this.mWaitingViewDelayer == null) {
			this.mWaitingViewDelayer = new Runnable() {

				@Override
				public void run() {
					updateWaitingViewState();
				}
			};
		}
		this.mWaitingViewHandler.postDelayed(mWaitingViewDelayer, 400);
	}

	protected void updateWaitingViewState() {
		this.mWaitingViewHandler.removeCallbacksAndMessages(null);
		if ((!mBusy) && this.mNetQueue.isRunInBackground()
				&& this.mDbQueue.isRunInBackground()) {
			this.hideWaiting();
		} else {
			this.showWaiting();
		}
	}

	protected void showWaiting() {
		if (this.mWaitingViewShowing) {
			return;
		}
		if (mWaitingView == null) {
			FrameLayout realWaitingView = new FrameLayout(this);
			this.mWaitingViewParams = new WindowManager.LayoutParams(
					ViewGroup.LayoutParams.MATCH_PARENT,
					ViewGroup.LayoutParams.MATCH_PARENT,
					WindowManager.LayoutParams.TYPE_APPLICATION,
					WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
							| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
					PixelFormat.TRANSPARENT);
			View virtualWaitingView;// 用于实现动画，由于WindowManager添加的View不能拥有自定义动画
			View waitingViewLayout = this.getWaitingViewLayout();
			if (waitingViewLayout != null) {
				virtualWaitingView = waitingViewLayout;
			} else {
				RelativeLayout defaultWaitingView = new RelativeLayout(this);
				View makLayer = new View(this);
				makLayer.setBackgroundColor(0x30000000);
				defaultWaitingView.addView(makLayer,
						new RelativeLayout.LayoutParams(
								RelativeLayout.LayoutParams.MATCH_PARENT,
								RelativeLayout.LayoutParams.MATCH_PARENT));
				ProgressBar progressBar = new ProgressBar(this, null,
						android.R.attr.progressBarStyleLarge);
				RelativeLayout.LayoutParams progressBarParams = new RelativeLayout.LayoutParams(
						RelativeLayout.LayoutParams.WRAP_CONTENT,
						RelativeLayout.LayoutParams.WRAP_CONTENT);
				progressBarParams.addRule(RelativeLayout.CENTER_IN_PARENT);
				defaultWaitingView.addView(progressBar, progressBarParams);
				virtualWaitingView = defaultWaitingView;
			}
			realWaitingView.addView(virtualWaitingView,
					new FrameLayout.LayoutParams(
							FrameLayout.LayoutParams.MATCH_PARENT,
							FrameLayout.LayoutParams.MATCH_PARENT));
			this.mWaitingView = realWaitingView;
			mWaitingViewFadeInAnim = new AlphaAnimation(0, 1);
			mWaitingViewFadeInAnim.setDuration(200);
			mWaitingViewFadeInAnim.setFillAfter(true);
			mWaitingViewFadeOutAnim = new AlphaAnimation(1, 0);
			mWaitingViewFadeOutAnim.setDuration(200);
			mWaitingViewFadeOutAnim.setFillAfter(true);
			mWaitingViewFadeOutAnim
					.setAnimationListener(new AnimationListener() {

						@Override
						public void onAnimationStart(Animation animation) {

						}

						@Override
						public void onAnimationRepeat(Animation animation) {

						}

						@Override
						public void onAnimationEnd(Animation animation) {
							hideWaitingNow();
						}
					});
		}
		this.getWindowManager().addView(mWaitingView, mWaitingViewParams);
		View virtualWaitingView = this.mWaitingView.getChildAt(0);
		virtualWaitingView.clearAnimation();
		virtualWaitingView.startAnimation(mWaitingViewFadeInAnim);
		this.mWaitingViewShowing = true;
	}

	protected void hideWaiting() {
		if (!mWaitingViewShowing) {
			return;
		}
		View virtualWaitingView = this.mWaitingView.getChildAt(0);
		virtualWaitingView.clearAnimation();
		virtualWaitingView.startAnimation(mWaitingViewFadeOutAnim);
	}

	protected void hideWaitingNow() {
		if (!mWaitingViewShowing) {
			return;
		}
		this.getWindowManager().removeView(mWaitingView);
		this.mWaitingViewShowing = false;
	}

	protected View getWaitingViewLayout() {
		return null;
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		OWrapper.onActivityResult(this, requestCode, resultCode, data);
		super.onActivityResult(requestCode, resultCode, data);
	}

	public void add(INetTask<?, ?> task) {
		this.bind(task);
		if(mNetQueue == null){
			mNetQueue = new NetQueue();
			mNetQueue.setContext(this);
			mNetQueue.addListener(mNetQueueListener);
		}
		mNetQueue.add(task);
	}

	public void add(IDbTask<?, ?> task) {
		this.bind(task);
		mDbQueue.add(task);
	}

	public void add(IDownloadTask task) {
		Context appContext = this.getApplicationContext();
		if (appContext instanceof IDownloadQueueOwner) {
			((IDownloadQueueOwner) appContext).getDownloadQueue().add(task);
		}
	}

	public void add(ISocketTask<?, ?> task) {
		this.bind(task);
		Context appContext = this.getApplicationContext();
		if (appContext instanceof ISocketQueueOwner) {
			((ISocketQueueOwner) appContext).getSocketQueue().add(task);
		}
	}

	@Override
	public void notify(Object message) {
		if (message == null) {
			return;
		}
		if (message instanceof CookieExpiredException) {
			if (this instanceof IPrivateActivity) {
				((IPrivateActivity) this).refresh();
			}
		}
	}

	@Override
	public void finish() {
		hidePatternNow();
		hideWaitingNow();
		super.finish();
	}

	@Override
	public void stopAll() {
		OWrapper.stopAll(this);
	}

	@Override
	public void stopAll(boolean includeLockable) {
		OWrapper.stopAll(this, includeLockable);
	}

	@Override
	public <T extends View> T findViewById(int id, Class<T> viewClass) {
		View v = this.findViewById(id);
		if (v != null) {
			if (viewClass != null) {
				if (viewClass.isInstance(v)) {
					return (T) v;
				} else {
					return null;
				}
			}
			return (T) v;
		}
		if (mBindViews != null) {
			for (IStateView stateView : mBindViews) {
				T view = stateView.findViewById(id, viewClass);
				if (view != null) {
					return view;
				}
			}
		}
		return null;
	}

	@Override
	public List<IStateView> getBindStateViews() {
		if (mBindViews == null) {
			mBindViews = new ArrayList<IStateView>();
		}
		return mBindViews;
	}

	@Override
	public List<IStopable> getBindStopables() {
		if (mBindStopables == null) {
			mBindStopables = new LinkedList<IStopable>();
		}
		return mBindStopables;
	}

	@Override
	public boolean redirectToSelectedView() {
		return false;
	}

	@Override
	public IStateView getSelectedView() {
		return null;
	}

	@Override
	public List<OnActivityResultListener> getOnActivityResultListeners() {
		return mDispatcher.getListeners(OnActivityResultListener.EVENT_TYPE,
				OnActivityResultListener.class);
	}

	@Override
	public void addOnActivityResultListener(OnActivityResultListener listener) {
		mDispatcher.addListener(OnActivityResultListener.EVENT_TYPE, listener);
	}

	@Override
	public void removeOnActivityResultListener(OnActivityResultListener listener) {
		mDispatcher.removeListener(OnActivityResultListener.EVENT_TYPE,
				listener);
	}

}
